/* Copyright (C) 2000-2012 by George Williams */
/*
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:

 * Redistributions of source code must retain the above copyright notice, this
 * list of conditions and the following disclaimer.

 * Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.

 * The name of the author may not be used to endorse or promote products
 * derived from this software without specific prior written permission.

 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#include "gdraw.h"
#include "gresource.h"
#include "ggadgetP.h"

GBox _GGroup_LineBox = GBOX_EMPTY; /* Don't initialize here */
static GBox group_box = GBOX_EMPTY; /* Don't initialize here */
static int ggroup_inited = false;

static GGadgetCreateData gline_gcd[] = {
    { GLineCreate, { { 0, 0, 100, 0 }, NULL, 0, 0, 0, 0, 0, NULL, { NULL }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL }
};
static GGadgetCreateData *larray[] = { GCD_Glue, &gline_gcd[0], GCD_Glue, NULL, NULL };
static GGadgetCreateData linebox =
    { GHVGroupCreate, { { 2, 2, 0, 0 }, NULL, 0, 0, 0, 0, 0, NULL, { (GTextInfo *) larray }, gg_visible|gg_enabled, NULL, NULL }, NULL, NULL };
GResInfo gline_ri = {
    NULL, &ggadget_ri, NULL, NULL,
    &_GGroup_LineBox,
    NULL,
    &linebox,
    NULL,
    N_("Line"),
    N_("A separator line drawn across a dialog or in a menu"),
    "GLine",
    "Gdraw",
    false,
    omf_border_type|omf_border_shape|omf_padding,
    NULL,
    GBOX_EMPTY,
    NULL,
    NULL,
    NULL
};

void _GGroup_Init(void) {
    if ( ggroup_inited )
return;
    _GGadgetCopyDefaultBox(&_GGroup_LineBox);
    _GGadgetCopyDefaultBox(&group_box);
    group_box.border_type = _GGroup_LineBox.border_type = bt_engraved;
    group_box.border_shape = _GGroup_LineBox.border_shape = bs_rect;
    group_box.padding = _GGroup_LineBox.padding = 0;
    /*group_box.flags = _GGroup_LineBox.flags = 0;*/
    group_box.main_background = COLOR_TRANSPARENT;
    group_box.disabled_background = COLOR_TRANSPARENT;
    _GGadgetInitDefaultBox("GLine.",&_GGroup_LineBox,NULL);
    _GGadgetInitDefaultBox("GGroup.",&group_box,NULL);
    ggroup_inited = true;
}

static int ggroup_expose(GWindow pixmap, GGadget *g, GEvent *event) {
    GRect old1, border;

    if ( g->state == gs_invisible )
return( false );

    GDrawPushClip(pixmap,&g->r,&old1);
    /* Background should be transpearant */
    /*GBoxDrawBackground(pixmap,&g->r,g->box, g->state,false);*/
    border = g->r;
    if ( g->prevlabel ) {
	int off = (g->prev->r.height-GBoxBorderWidth(g->base,g->box))/2;
	border.y += off; border.height -= off;
    }
    GBoxDrawBorder(pixmap,&border,g->box,g->state,false);

    GDrawPopClip(pixmap,&old1);
return( true );
}

static int gline_expose(GWindow pixmap, GGadget *g, GEvent *event) {
    GRect old1;

    if ( g->state == gs_invisible )
return( false );

    GDrawPushClip(pixmap,&g->r,&old1);
    if ( g->vert )
	GBoxDrawVLine(pixmap,&g->r,g->box);
    else
	GBoxDrawHLine(pixmap,&g->r,g->box);
    GDrawPopClip(pixmap,&old1);
return( true );
}

static void GGroupGetDesiredSize(GGadget *g, GRect *outer, GRect *inner) {
    if ( outer!=NULL ) {
	int bp = GBoxBorderWidth(g->base,g->box);
	outer->x = outer->y = 0;
	outer->width = outer->height = 2*bp+2;
	if ( g->desired_width>0 ) outer->width = g->desired_width;
	if ( g->desired_height>0 ) outer->height = g->desired_height;
    }
    if ( inner!=NULL ) {
	inner->x = inner->y = 0;
	inner->width = inner->height = 1;
    }
}

struct gfuncs gline_funcs = {
    0,
    sizeof(struct gfuncs),

    gline_expose,
    _ggadget_noop,
    _ggadget_noop,
    NULL,
    NULL,
    NULL,
    NULL,

    _ggadget_redraw,
    _ggadget_move,
    _ggadget_resize,
    _ggadget_setvisible,
    _ggadget_setenabled,
    _ggadget_getsize,
    _ggadget_getinnersize,

    _ggadget_destroy,

    NULL,
    NULL,
    NULL,
    NULL,
    NULL,

    NULL,
    NULL,

    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,

    GGroupGetDesiredSize,
    _ggadget_setDesiredSize,
    NULL,
    NULL
};

struct gfuncs ggroup_funcs = {
    0,
    sizeof(struct gfuncs),

    ggroup_expose,
    _ggadget_noop,
    _ggadget_noop,
    NULL,
    NULL,
    NULL,
    NULL,

    _ggadget_redraw,
    _ggadget_move,
    _ggadget_resize,
    _ggadget_setvisible,
    _ggadget_setenabled,
    _ggadget_getsize,
    _ggadget_getinnersize,

    _ggadget_destroy,

    NULL,
    NULL,
    NULL,
    NULL,
    NULL,

    NULL,
    NULL,

    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,

    GGroupGetDesiredSize,
    _ggadget_setDesiredSize,
    NULL,
    NULL
};

static void GLineFit(GGadget *g) {
    int bp = GBoxBorderWidth(g->base,g->box);

    if ( g->r.width==0 && !g->vert ) {
	GRect size;
	GDrawGetSize(g->base,&size);
	g->r.width = size.width - g->r.x - GDrawPointsToPixels(g->base,_GGadget_Skip);
    }
    if ( g->r.height==0 && !g->vert )
	g->r.height = bp;
    if ( g->r.width==0 && g->vert )
	g->r.width = bp;
    g->inner = g->r;
    g->inner.width = g->inner.height = 0;
}

static void GGroupFit(GGadget *g) {
    int bp = GBoxBorderWidth(g->base,g->box);

    if ( g->r.width==0 || g->r.height==0 )
	g->opengroup = true;
    g->inner = g->r;
    g->inner.x += bp;
    if ( g->prevlabel )
	g->inner.y += (g->prev->r.height-bp)/2 + bp;
    else
	g->inner.y += bp;
    if ( g->r.width != 0 )
	g->inner.width = g->r.width - 2*bp;
    if ( g->r.height != 0 )
	g->inner.height = g->r.y + g->r.height - bp - g->inner.y;
}

GGadget *GLineCreate(struct gwindow *base, GGadgetData *gd,void *data) {
    GGadget *g = gcalloc(1,sizeof(GLine));

    if ( !ggroup_inited )
	_GGroup_Init();
    g->funcs = &gline_funcs;
    _GGadget_Create(g,base,gd,data,&_GGroup_LineBox);
    if ( gd->flags & gg_line_vert )
	g->vert = true;

    GLineFit(g);
    _GGadget_FinalPosition(g,base,gd);
return( g );
}

GGadget *GGroupCreate(struct gwindow *base, GGadgetData *gd,void *data) {
    GGadget *g = gcalloc(1,sizeof(GGroup));

    if ( !ggroup_inited )
	_GGroup_Init();
    g->funcs = &ggroup_funcs;
    _GGadget_Create(g,base,gd,data,&group_box);

    if ( (gd->flags&gg_group_prevlabel) && g->prev!=NULL )
	g->prevlabel = true;
    if ( g->prevlabel && gd->pos.x==0 )
	g->r.x = g->prev->r.x - GDrawPointsToPixels(base,_GGadget_Skip);
    GGroupFit(g);
    _GGadget_FinalPosition(g,base,gd);
return( g );
}

GResInfo *_GLineRIHead(void) {

    _GGroup_Init();
return( &gline_ri );
}
